package org.irri.smta.util;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;

import org.apache.commons.io.FileUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.ByteArrayBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class HttpPostUtils {

	private static final Logger LOGGER = LoggerFactory
			.getLogger(HttpPostUtils.class);

	/**
	 * Method that builds the multi-part form data request
	 * 
	 * @param file
	 *            the actual file instance that needs to be uploaded
	 * @param urlString
	 *            the urlString to which the file needs to be uploaded
	 * @param username
	 *            the username
	 * @param password
	 *            the password
	 * @compressed true if file is gzip compressed; false otherwise
	 * @return server response as <code>String</code>
	 */
	public String executeMultiPartRequest(File file, String urlString,
			String username, String password, boolean compressed)
			throws Exception {

		HttpPost postRequest = new HttpPost(urlString);
		try {

			MultipartEntity multiPartEntity = new MultipartEntity(
					HttpMultipartMode.BROWSER_COMPATIBLE);

			// The usual form parameters can be added this way
			multiPartEntity.addPart("username",
					new StringBody(username != null ? username : "",
							"text/plain", Charset.forName("UTF-8")));
			multiPartEntity.addPart("password",
					new StringBody(password != null ? password : "",
							"text/plain", Charset.forName("UTF-8")));
			multiPartEntity.addPart("compressed",
					new StringBody(compressed ? "y" : "n", "text/plain",
							Charset.forName("UTF-8")));

			/*
			 * Construct a FileBody containing the file contents as byte array
			 * of the file that needs to be attached and specify the MIME type
			 * of the file. Add the fileBody to the request as an another part.
			 * This part will be considered as file part and the rest of as
			 * usual form-data parts.
			 */
			byte bytes[] = FileUtils.readFileToByteArray(file);
			ByteArrayBody fileBody = new ByteArrayBody(bytes, null);
			multiPartEntity.addPart("xml", fileBody);

			postRequest.setEntity(multiPartEntity);
		} catch (UnsupportedEncodingException e) {
			LOGGER.error(e.getMessage());
			throw new Exception(e);
		}

		return executeRequest(postRequest);
	}

	/**
	 * A generic method to execute any type of HTTP Request and constructs a
	 * response object.
	 * 
	 * @param requestBase
	 *            the request that needs to be executed
	 * @return server response as <code>String</code>
	 */
	private static String executeRequest(HttpRequestBase requestBase)
			throws Exception {
		String responseString = "";

		HttpClient client = new DefaultHttpClient();
		client.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION,
				HttpVersion.HTTP_1_1);
		try {
			HttpResponse response = client.execute(requestBase);
			HttpEntity responseEntity = response.getEntity();
			responseString = EntityUtils.toString(responseEntity, "UTF-8");
		} catch (ClientProtocolException e) {
			LOGGER.error(e.getMessage());
			throw new Exception(e);
		} catch (IOException e) {
			LOGGER.error(e.getMessage());
			throw new Exception(e);
		}
		client.getConnectionManager().shutdown();

		return responseString;
	}

	public String postFile(File file, String urlString, String username,
			String password, boolean compressed) throws Exception {
		HttpPostUtils utils = new HttpPostUtils();
		String response = utils.executeMultiPartRequest(file,
				urlString, username, password, compressed);
		return response;
	}

/*
	private String executeRequest(HttpRequestBase requestBase)
			throws Exception {
		String responseString = "";

		HttpClient client = getNewHttpClient();
		try {
			HttpResponse response = client.execute(requestBase);
			HttpEntity responseEntity = response.getEntity();
			responseString = EntityUtils.toString(responseEntity, "UTF-8");
		} catch (ClientProtocolException e) {
			LOGGER.error(e.getMessage());
			throw new Exception(e);
		} catch (IOException e) {
			LOGGER.error(e.getMessage());
			throw new Exception(e);
		}
		client.getConnectionManager().shutdown();

		return responseString;
	}

	class MySSLSocketFactory extends SSLSocketFactory {
	    SSLContext sslContext = SSLContext.getInstance("TLS");

	    public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
	        super(truststore);

	        TrustManager tm = new X509TrustManager() {
	            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
	            }

	            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
	            }

	            public X509Certificate[] getAcceptedIssuers() {
	                return null;
	            }
	        };

	        sslContext.init(null, new TrustManager[] { tm }, null);
	    }

	    @Override
	    public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
	        return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
	    }

	    @Override
	    public Socket createSocket() throws IOException {
	        return sslContext.getSocketFactory().createSocket();
	    }
	}
	
	public HttpClient getNewHttpClient() {
	    try {
	        KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
	        trustStore.load(null, null);

	        SSLSocketFactory sf = new MySSLSocketFactory(trustStore);
	        sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

	        HttpParams params = new BasicHttpParams();
	        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
	        HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);

	        SchemeRegistry registry = new SchemeRegistry();
	        registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
	        registry.register(new Scheme("https", sf, 443));

	        ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);

	        return new DefaultHttpClient(ccm, params);
	    } catch (Exception e) {
	        return new DefaultHttpClient();
	    }
	}
*/

/*
	private void doTest() {
		try {
			postFile(new File("C:/temp/smta-sample.xml.gz"),
					"https://www.itworks.it/itt/index.php?r=extsys/uploadxml",
					"IRRI", "R1sv0ltO", true);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public static void main(String args[]) {
		HttpPostUtils hpu = new HttpPostUtils();
		hpu.doTest();
	}
*/
}
